<?php
/**
 * Object registry.
 *
 * A repository for objects, each registered with a key.
 *
 * @copyright     Copyright 2008-2010, LilCake.net
 * @link          http://lilcake.net LilCake.net
 * @package       lil
 * @subpackage    lil
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */

/**
 * Class Collections.
 *
 * A repository for objects, each registered with a key.
 * If you try to add an object with the same key twice, nothing will come of it.
 * If you need a second instance of an object, give it another key.
 *
 * @package       lil
 * @subpackage    lil.libs
 */
class LilObjectRegistry {

/**
 * Names of classes with their objects.
 *
 * @var array
 * @access protected
 */
	protected $__objects = array();

/**
 * Names of class names mapped to the object in the registry.
 *
 * @var array
 * @access protected
 */
	protected $__map = array();

/**
 * Return a singleton instance of the LilPluginRegistry.
 *
 * @return LilPluginRegistry instance
 * @access public
 */
	public static function &getInstance() {
		static $instance = array();
		if (!$instance) {
			$instance =& new LilObjectRegistry();
		}
		return $instance;
	}

/**
 * Add $object to the registry, associating it with the name $key.
 *
 * @param string $key	Key for the object in registry
 * @param mixed $object	Object to store
 * @return boolean True if the object was written, false if $key already exists
 * @access public
 * @static
 */
	public static function addObject($key, &$object) {
		$_this =& LilObjectRegistry::getInstance();
		$key = Inflector::underscore($key);
		if (!isset($_this->__objects[$key])) {
			$_this->__objects[$key] =& $object;
			return true;
		}
		return false;
	}

/**
 * Remove object which corresponds to given key.
 *
 * @param string $key	Key of object to remove from registry
 * @return void
 * @access public
 * @static
 */
	public static function removeObject($key) {
		$_this =& LilObjectRegistry::getInstance();
		$key = Inflector::underscore($key);
		if (isset($_this->__objects[$key])) {
			unset($_this->__objects[$key]);
		}
	}

/**
 * Returns true if given key is present in the LilPluginRegistry.
 *
 * @param string $key Key to look for
 * @return boolean true if key exists in registry, false otherwise
 * @access public
 * @static
 */
	public static function isKeySet($key) {
		$_this =& LilObjectRegistry::getInstance();
		$key = Inflector::underscore($key);
		if (isset($_this->__objects[$key])) {
			return true;
		} elseif (isset($_this->__map[$key])) {
			return true;
		}
		return false;
	}

/**
 * Get all keys from the registry.
 *
 * @return array Set of keys stored in registry
 * @access public
 * @static
 */
	public static function keys() {
		$_this =& LilObjectRegistry::getInstance();
		return array_keys($_this->__objects);
	}

/**
 * Return object which corresponds to given key.
 *
 * @param string $key Key of object to look for
 * @return mixed Object stored in registry or boolean false if the object does not exist.
 * @access public
 * @static
 */
	public static function &getObject($key) {
		$_this =& LilObjectRegistry::getInstance();
		$key = Inflector::underscore($key);
		$return = false;
		if (isset($_this->__objects[$key])) {
			$return =& $_this->__objects[$key];
		} else {
			$key = $_this->__getMap($key);
			if (isset($_this->__objects[$key])) {
				$return =& $_this->__objects[$key];
			}
		}
		return $return;
	}

/**
 * Checks to see if $alias is a duplicate $class Object
 *
 * @param string $alias
 * @param string $class
 * @return boolean
 * @access private
 * @static
 */
	public static function &__duplicate($alias,  $class) {
		$duplicate = false;
		if ($this->isKeySet($alias)) {
			$model =& $this->getObject($alias);
			if (is_object($model) && (is_a($model, $class) || $model->alias === $class)) {
				$duplicate =& $model;
			}
			unset($model);
		}
		return $duplicate;
	}

/**
 * Add a key name pair to the registry to map name to class in the registry.
 *
 * @param string $key Key to include in map
 * @param string $name Key that is being mapped
 * @access public
 * @static
 */
	public static function map($key, $name) {
		$_this =& LilObjectRegistry::getInstance();
		$key = Inflector::underscore($key);
		$name = Inflector::underscore($name);
		if (!isset($_this->__map[$key])) {
			$_this->__map[$key] = $name;
		}
	}

/**
 * Get all keys from the map in the registry.
 *
 * @return array Keys of registry's map
 * @access public
 * @static
 */
	public static function mapKeys() {
		$_this =& LilObjectRegistry::getInstance();
		return array_keys($_this->__map);
	}

/**
 * Return the name of a class in the registry.
 *
 * @param string $key Key to find in map
 * @return string Mapped value
 * @access private
 * @static
 */
	private function __getMap($key) {
		if (isset($this->__map[$key])) {
			return $this->__map[$key];
		}
	}

/**
 * Flushes all objects from the LilPluginRegistry.
 *
 * @return void
 * @access public
 * @static
 */
	public static function flush() {
		$_this =& LilObjectRegistry::getInstance();
		$_this->__objects = array();
		$_this->__map = array();
	}

/**
 * Returns number of objects in LilPluginRegistry
 *
 * @return int
 * @access public
 * @static
 */
	public static function count() {
		$_this =& LilObjectRegistry::getInstance();
		return sizeof($_this->__objects);
	}
}